How to display NotFound when invalid hash is matched in SAPUI5 - sapui5

I did the steps to catch and handle invalid hashes with SAPUI5 but my application is not working.
When i try to navigate to NotFound view changing the Hash i only gets an Info message:
But the view isn't displayed.
[EDIT]:
Adding source code files:
Here i added the bypassed section
I've created the target in Targets section of the manifest:
This is the NotFound.controller.js
sap.ui.define([
"my/path/controller/BaseController"
], function (BaseController) {
"use strict";
return BaseController.extend("my.path.controller.NotFound", {
onInit: function () {
var oRouter, oTarget;
oRouter = this.getRouter();
oTarget = oRouter.getTarget("NotFound");
oTarget.attachDisplay(function (oEvent) {
this._oData = oEvent.getParameter("data"); // store the data
}, this);
},
// override the parent's onNavBack (inherited from BaseController)
onNavBack : function (oEvent){
// in some cases we could display a certain target when the back button is pressed
if (this._oData && this._oData.fromTarget) {
this.getRouter().getTargets().display(this._oData.fromTarget);
delete this._oData.fromTarget;
return;
}
// call the parent's onNavBack
BaseController.prototype.onNavBack.apply(this, arguments);
}
});
});
Here the NotFound.view.xml:
<mvc:View
controllerName="my.path.controller.NotFound"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc">
<MessagePage
title="{i18n>NotFound}"
text="{i18n>NotFound.text}"
description="{i18n>NotFound.description}"
showNavButton="true"
navButtonPress="onNavBack"/>
</mvc:View>
And here the onInit method at the App controller:
onInit: function(){
jQuery.sap.log.setLevel(jQuery.sap.log.Level.INFO);
var oRouter = this.getRouter();
oRouter.attachBypassed(function (oEvent) {
var sHash = oEvent.getParameter("hash");
// do something here, i.e. send logging data to the backend for analysis
// telling what resource the user tried to access...
jQuery.sap.log.info("Sorry, but the hash '" + sHash + "' is invalid.", "The resource was not found.");
});
oRouter.attachRouteMatched(function (oEvent){
var sRouteName = oEvent.getParameter("name");
// do something, i.e. send usage statistics to backend
// in order to improve our app and the user experience (Build-Measure-Learn cycle)
jQuery.sap.log.info("User accessed route " + sRouteName + ", timestamp = " + new Date().getTime());
});
}
and
Any can help me?
Regards,

Check this plunker:
https://plnkr.co/edit/pxOkRSM8c97hXO6gkbpV
The key config is this on manifest.json:
"targets": {
"tgHome": {
"viewPath": "sapui5Example",
"viewName": "home"
},
"notFound": {
"viewPath": "sapui5Example",
"viewName": "NotFound",
"transition": "show"
}
}
To fire the 'not found' route, download the plunker and in the URL, after the hash just type anything and you will the the not Found Page (if you do it directly on plunker it won't work). Here is a pic:

Related

Refresh custom control in sapui5 when model change

I've a custom control which have multiple properties inserted in Detail View page. I've binded data with these properties. Scenario is I've two pages one is list view and then detail view. I've to navBack from detail page and select diff product from main page.Detail view page show diff products detail according to selected product. everything works fine. but problem is that my custom control doesn't update values and other page have updated values.
<custom:product topic="" subTopic="{product>name}" id="productDetial"></custom:product>
I've used one methond this.getView().byId("productDetail").rerender(); but it doesn't update my Inner HTML of control.
the control code. might be some typos error.as I've changed some variables name and remove unwanted code. the purpose is to show the methods which I've used and how I did
sap.ui.define([
"sap/m/Label",
"sap/m/Button",
"sap/m/CustomTile"
], function(Label, Button, CustomTile) {
"use strict";
jQuery.sap.declare("testProduct.control.product");
return CustomTile.extend("testProduct.control.product", {
metadata: { // the Control API
properties: {
name: {
type: "string",
defaultValue: "--"
},
subTopic: {
type: "string",
defaultValue: "--"
}
}
},
init: function() {
},
rerender: function(oRM, oControl) {
},
renderer: function(oRM, oControl) {
oRM.write('<div class=" sapMTile customTileCourseDetail">');
oRM.write('<div class="leftTileYourScore">');
if (oControl.getSubTopic() !== "" && oControl.getSubTopic() !== undefined) {
oRM.writeEscaped(oControl.getSubTopic());
} else {
oRM.write(" ");
}
oRM.write('</div>');
oRM.write('</div>
}
});
});
Yo just need to add a setter function in you control. When the binding is refreshed/changes, UI5 will trigger a setter method specific to the property. So in you case for the property subTopic it expects a method setSubTopic. This method should define you own logic to update said property in the UI layer according to your needs.
Here is part of the code you need to add, you will also have to tweak the initial rendering logic a bit.
renderer: function (oRM, oControl) {
//oRM.write('<div class=" sapMTile customTileCourseDetail">');
oRM.write("<div")
oRM.writeControlData(oControl);
oRM.addClass("sapMTile customTileCourseDetail");
oRM.writeClasses();
oRM.write(">");
oRM.write('<div class="leftTileYourScore">');
if (oControl.getSubTopic() !== "" && oControl.getSubTopic() !== undefined) {
oRM.writeEscaped(oControl.getSubTopic());
} else {
oRM.write(" ");
}
oRM.write('</div>');
oRM.write('</div>');
},
setSubTopic: function(sText){
this.setProperty("subTopic", sText, true);
$("#"+this.sId+" .leftTileYourScore").html(sText);
}

this._helloDialog in OpenUI5 walkthrough

I am new to JavaScript and OpenUI5.
I was going through the walkthrough demo on the openUi5 website OpenUI5 walkthrough demo
I came through the below code:
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/model/json/JSONModel",
"sap/ui/demo/wt/controller/HelloDialog"
], function(UIComponent, JSONModel, HelloDialog) {
"use strict";
return UIComponent.extend("sap.ui.demo.wt.Component", {
metadata: {
manifest: "json"
},
init: function() {
// call the init function of the parent
UIComponent.prototype.init.apply(this, arguments);
// set data model
var oData = {
recipient: {
name: "World"
}
};
var oModel = new JSONModel(oData);
this.setModel(oModel);
// set dialog
this._helloDialog = new HelloDialog(this.getRootControl());
},
openHelloDialog: function() {
this._helloDialog.open();
}
});
});
I have doubt in the line this._helloDialog = new HelloDialog(this.getRootControl());
If _helloDialog is not defined and we are using strict mode, then why does the system not throw message that _helloDialog is undefined?
_helloDialog is a property of this (the controller), and properties do not need to be initialized when creating an object.
"use strict"
var example = {};
example.newProperty = "i am a new property"; //This is absolutely correct
undefinedVariable = 1; // This is going to throw an error
Strict mode prevents you from implicitly creating global variables (as undefinedVariable = 1; would do). But it is not going to prevent adding a property to an object.
If you are interested on preventing the creation of properties, I suggest reading Freeze vs Seal

How to access Model from Controller in OpenUI5 Tutorial Step 7: JSON Model?

In the OpenUI5 Tutorial Step 7:JSON Model, I want to extend the tutorial. If the button is pressed, it should say Hello followed by the name entered in the text box. Could anybody help?
The code in question (provided by the OpenUI5 team) is:
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageToast",
"sap/ui/model/json/JSONModel"
], function (Controller, MessageToast, JSONModel) {
"use strict";
return Controller.extend("sap.ui.demo.wt.controller.App", {
onInit : function () {
// set data model on view
var oData = {
recipient : {
name : "World"
}
};
var oModel = new JSONModel(oData);
this.getView().setModel(oModel);
},
onShowHello : function () {
MessageToast.show("Hello World");
}
});
});
In order to access the model from the controller, you would simply do:
onShowHello : function () {
var oModel = this.getView().getModel(),
sName = oModel.getProperty("/recipient/name");
MessageToast.show("Hello, " + sName);
}
#SVM, in the future, please include code in your question so that others with the same problem (or those looking to help) do not have to follow a link that may or may not exist in the future. This may explain your question downvotes.

SAP UI5: Navigation from Master page and Detail page through two different OData URLs

I am trying to create a Master - Detail page using OData servicea in SAPUI5. Everything works fine in the Master page. Meaning I'm able to populate the list with valid data from SAP backend using an OData URL.
Now what I want to achieve is, to call a second OData URL to fetch the detail values and populate that in the page.
My Master.controller.js
handleListSelect : function (evt) {
var context = evt.getParameter("listItem").getBindingContext();
this.nav.to("Detail", context);
console.log('evt.getSource: ' + evt.getSource());
console.log('evt.getBindingContext: ' + evt.getSource().getBindingContext());
}
Console Output gives
"evt.getSource: Element sap.m.List#Master--list" sap-ui-core.js line 80 > eval:31
"evt.getBindingContext: undefined"
I'm unable to populate values in the detail page from the second URL. Can anyone guide or help me on this?
My Compenent.js
createContent : function() {
// create root view
var oView = sap.ui.view({
id : "app",
viewName : "sap.ui.demo.myFiori.view.App",
type : "JS",
viewData : {
component : this
}
});
// Using OData model to connect against a real service
var url = "/MyFioriUI5/proxy/sap/opu/odata/sap/XXXXXX;mo/";
var oModel = new sap.ui.model.odata.ODataModel(url, true, "", "");
oView.setModel(oModel);
// set i18n model
var i18nModel = new sap.ui.model.resource.ResourceModel({
bundleUrl : "i18n/messageBundle.properties"
});
oView.setModel(i18nModel, "i18n");
// set device model
var deviceModel = new sap.ui.model.json.JSONModel({
isPhone : jQuery.device.is.phone,
isNoPhone : !jQuery.device.is.phone,
listMode : (jQuery.device.is.phone) ? "None" : "SingleSelectMaster",
listItemType : (jQuery.device.is.phone) ? "Active" : "Inactive"
});
deviceModel.setDefaultBindingMode("OneWay");
oView.setModel(deviceModel, "device");
// Using a local model for offline development
// var oModel = new sap.ui.model.json.JSONModel("model/mock.json");
// oView.setModel(oModel);
// done
return oView;
}
My Detail.controller.js
sap.ui.controller("sap.ui.demo.myFiori.view.Detail", {
handleNavButtonPress : function(evt) {
this.nav.back("Master");
},
onBeforeRendering : function() {
// this.byId("SupplierForm").bindElement("BusinessPartner");
},
handleApprove : function(evt) {
// show confirmation dialog
var bundle = this.getView().getModel("i18n").getResourceBundle();
sap.m.MessageBox.confirm(bundle.getText("ApproveDialogMsg"), function(oAction) {
if (sap.m.MessageBox.Action.OK === oAction) {
// notify user
var successMsg = bundle.getText("ApproveDialogSuccessMsg");
sap.m.MessageToast.show(successMsg);
// TODO call proper service method and update model (not part of this session)
}
},
bundle.getText("ApproveDialogTitle"));
}
});
I can't see the second URL you are refering to, but we handle it this way.
In Component.js:
var oView = sap.ui.view({
id: "app",
viewName: "fom.test.app.view.App",
type: "JS",
viewData: { component : this }
});
var dataModel = new sap.ui.model.odata.ODataModel("/fom/fiori/odata/FOM/mobile_app_srv", true);
oView.setModel(dataModel);
This connects the master view to the data for all the list items.
In the App.controller.js we make use of the onNavigation function, defined in Detail.controller.js. That means when routing to the detail view, the onNavigation function is called before the view is set up.
App.controller.js:
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 : "fom.test.app.view.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);
try{
var oController = page.getController();
oController.onNavigation(context);
}
catch(e){ }
}
},
Detail.controller.js:
onNavigation: function(context) {
this.getView().bindElement({
path: context.sPath,
parameters: {
select: "Id," +
"Lifnam," +
"Rmwwr," +
"Waers," +
"Sendedatum," +
"Workflowtyp," +
"Sktodat," +
"Stufe," +
"MonFrgstA," +
"Bukrs," +
"Belnr," +
"Gjahr," +
"EdcObject," +
"BstatTxt",
expand: "Positions"
}
});
},
The bindElements() function, connects the detail view to the results of another web service call, which fetches all attributes mentioned in select and the line items which are fetched with the expand.
Now your first webservice call is loading only the data relevant for the master view list, and the second one all the information of the selected list item.
When you use the newer routing functionality of UI5, you will need to find another place for the hook. I haven't built that in yet.
oView.setModel(oModel);
You have this statement twice - the one would override the other - you need to provide an alternate reference to the second instance:
e.g.
oView.setModel(oModel, "local")

How to manage newly created objects without "saving" before transitioning to a new route it in emberjs?

I have an issue where I have a resource with a new route. When I transition to that new route I create a new object. On the form I have button to cancel, which removes that object. However, if I click a link on my navigation, say going back to the resource index, that object is there with whatever I put in the form. What's the best way of managing creating objects then moving away from the form?
My routes:
App.Router.map(function() {
this.resource('recipes', function() {
this.route('new');
this.route('show', { path: '/:recipe_id' });
});
this.resource('styles');
});
App.RecipesNewRoute = Ember.Route.extend({
model: function() {
return App.Recipe.createRecord({
title: '',
description: '',
instructions: ''
});
},
setupController: function(controller, model) {
controller.set('styles', App.Style.find());
controller.set('content', model);
}
});
My controller for the new route:
App.RecipesNewController = Ember.ObjectController.extend({
create: function() {
this.content.validate()
if(this.content.get('isValid')) {
this.transitionToRoute('recipes.show', this.content);
}
},
cancel: function() {
this.content.deleteRecord();
this.transitionToRoute('recipes.index');
},
buttonTitle: 'Add Recipe'
});
I'm using version 1.0.0.rc.1
Thanks!
Any code that you place in the deactivate method of your route will get executed every time you leave that route. The following code will delete the new model if the user hasn't explicitly saved it.
App.RecipesNewRoute = Ember.Route.extend({
// ...
deactivate: function() {
var controller = this.controllerFor('recipes.new');
var content = controller.get('content');
if (content && content.get('isNew') && !content.get('isSaving'))
content.deleteRecord();
},
// ...
});
As an added bonus, you now don't need to explicitly delete the record when the user presses the cancel button.