SAPUI5/OpenUI5 view not rendered after router navTo - view

I'm creating SAPUI5 sample app with simple routing (SAPUI5/OpenUI5 v.1.22).
My main problem, which I'm trying to understand, why URL pattern changes and the onInit of target view controller is fired, but after nothing happens (onAfterRendering not fired), and I'm able to go to another page only after page reload.
Routing setup. Compontent.js, where router is initialized, is structured in following way:
sap.ui.define([
"sap/ui/core/UIComponent"
], function (UIComponent) {
return UIComponent.extend("sge.apps.app.Component", {
metadata:{
name : "Sample App",
version : "1.0",
includes : [],
dependencies : {
libs : ["sap.m", "sap.ui.layout"],
components : []
},
rootView: "sge.apps.app.view.App",
config: {
resourceBundle: "i18n/i18n.properties"
},
routing : {
config : {
routerClass : sap.ui.core.routing.Router,
viewType : "XML",
viewPath : "sge.apps.app.view",
targetControl: "app",
targetAggregation: "pages",
transition: "slide",
clearTarget : false,
bypassed: {
target: "notFound"
}
},
routes: [{
pattern: "",
name: "appHome",
view: "Home"
},{
pattern : ":all*:",
name : "catchallDetail",
view : "NotFound",
transition : "show"
},{
pattern: "notFound",
name: "appNotFound",
view: "NotFound",
transition : "show"
}]
}
},
init : function() {
UIComponent.prototype.init.apply(this, arguments);
var mConfig = this.getMetadata().getConfig();
// always use absolute paths relative to our own component
// (relative paths will fail if running in the Fiori Launchpad)
var rootPath = jQuery.sap.getModulePath("sge.apps.app");
// set i18n model
var i18nModel = new sap.ui.model.resource.ResourceModel({
bundleUrl : [rootPath, mConfig.resourceBundle].join("/")
});
this.setModel(i18nModel, "i18n");
// set device model
var deviceModel = new sap.ui.model.json.JSONModel({
isTouch : sap.ui.Device.support.touch,
isNoTouch : !sap.ui.Device.support.touch,
isPhone : sap.ui.Device.system.phone,
isNoPhone : !sap.ui.Device.system.phone,
listMode : sap.ui.Device.system.phone ? "None" : "SingleSelectMaster",
listItemType : sap.ui.Device.system.phone ? "Active" : "Inactive"
});
deviceModel.setDefaultBindingMode("OneWay");
this.setModel(deviceModel, "device");
this.getRouter().initialize();
}
});
});
I have Home.controller.js of the Home.view.xml from where I try to navigate to another view, by pressing the button with event onDisplayNotFound:
sap.ui.define([
"sge/apps/app/controller/BaseController"
], function (BaseController) {
"use strict";
return BaseController.extend("sge.apps.app.controller.Home", {
onDisplayNotFound : function (oEvent) {
this.getRouter().navTo("appNotFound");
}
});
});
BaseController.js
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/routing/History"
], function (Controller, History) {
"use strict";
return Controller.extend("sge.apps.app.controller.BaseController", {
getRouter: function () {
return sap.ui.core.UIComponent.getRouterFor(this);
},
onNavBack: function (oEvent) {
var oHistory, sPreviousHash;
oHistory = History.getInstance();
sPreviousHash = oHistory.getPreviousHash();
if(sPreviousHash !== undefined) {
window.history.go(-1);
} else {
this.getRouter().navTo("appHome", {}, true /*no history*/);
}
}
});
});
NotFound.controller.js of target view NotFound.view.xml:
sap.ui.define([
"sge/apps/app/controller/BaseController"
], function (BaseController) {
"use strict";
return BaseController.extend("sge.apps.app.controller.NotFound", {
onInit: function () {
console.log("onInit NotFound.view.xml");
},
onAfterRendering: function () {
console.log("onAfterRendering NotFound.view.xml");
}
});
});

I had the same problem and I solved by adding this line in the configuration of the routing :
"routerClass" : "sap.m.routing.Router",
And it has worked perfectly navigation.
"routing": {
"config": {
"routerClass" : "sap.m.routing.Router",
"viewPath": "es.seidor.view",
"controlId": "App",
"async" : "true",
"clearTarget" : "true"
}

sap.ui.define is a feature of UI5 v1.30
Either update the version you're using to 1.30.x or remove the sap.ui.define code and replace it with code that works with the earlier versions.
Pre-sap.ui.define code looks something like this:
jQuery.sap.require("sap.m.Button");
//use jQuery.sap.require to require any controls or other files
sap.ui.controller("my.controller", {
onInit: function(){
//your code here
//doing something with sap.m.Button, won't work without the require
//var oBtn = new sap.m.Button("myBtn", {text: "Click me"});
},
onAfterRendering: function(){
//more code
}
});
Try that.

The solution is simple, just use some part of TDG best practice:
Create the file MyRouter.js
sap.ui.define([
"sap/ui/core/routing/Router",
"sap/m/routing/RouteMatchedHandler"
], function (Router, RouteMatchedHandler) {
"use strict";
return Router.extend("sge.apps.notespese.MyRouter", {
constructor : function() {
sap.ui.core.routing.Router.apply(this, arguments);
this._oRouteMatchedHandler = new sap.m.routing.RouteMatchedHandler(this);
},
destroy : function() {
sap.ui.core.routing.Router.prototype.destroy.apply(this, arguments);
this._oRouteMatchedHandler.destroy();
}
});
});
Inject it in your Component.js, as follows:
sap.ui.define([
"sap/ui/core/UIComponent",
"sge/apps/notespese/MyRouter"
], function (UIComponent, MyRouter) {
"use strict";
return UIComponent.extend("sge.apps.notespese.Component", {
...
In Component metadata section replace
routing : {
config : {
routerClass : sap.ui.core.routing.Router,
with
routing : {
config : {
routerClass : sge.apps.notespese.MyRouter,
Hope to do not forget other this question related things.

Related

vue.js Failed to mount component: template

i am working hard to solve this issue but not found any one please help me about this
here is my code
calling component
Vue.component('select2', require('./components/select2.vue'));
html of component
<template>
<select>
<slot></slot>
</select>
</template>
here is my vue.js script
<script>
export default {
props: ['options', 'value', 'params'],
mounted: function () {
var vm = this;
var params = !this.params ? {} : this.params;
params.val = this.value;
if(this.options) {
params.data = this.options;
}
$(this.$el).val(this.value);
$(this.$el).select2(params);
$(this.$el).on('change', function () {
vm.$emit('input', $(this).val())
})
$(this.$el).val(this.value).trigger('change');
},
watch: {
value: function (value) {
$(this.$el).val(value);
},
options: function (options) {
var params = !this.params ? {} : this.params;
if(this.options) {
params.data = this.options;
}
$(this.$el).select2(params);
}
},
destroyed: function () {
$(this.$el).off().select2('destroy')
}
}
</script>
but still getting this error i tried alot of things but not working please help me i can give you more detials if you needed i am using laravel ,gulp etc

ui-router set params from resolve

Hi I wondering is it possible set param in ui-router data which from resolve. This example doesen't work, what's wrong ?
resolve : {
userItem : [function () {
return "name";
}]
},
params: {
title: $resolve.userItem ,
},
How about something like this
//...
resolve: {
userItem: function($stateParams){
$stateParams.title = "whatever";
return {data: "whatever"};
}
},
params:{
title:null
}
//...

Marionette - throws error on `removeRegions` how to solve it

In my app, i have the regions as header,content,footer - in which on the login page, I don't want to use the header, and footer. for that, on onRender i remove the regions what i don't want to be.
But I am getting an error saying: Cannot read property 'empty' of undefined.
here is my template : (i use jade )
div#wrapper
script(type='text/template', id="appTemplate")
div#header
div#content
div#footer
script(type='text/template', id="loginTemplate")
div this is login template
here is my layout.js:
socialApp.AppLayout = Backbone.Marionette.LayoutView.extend({
el:'#wrapper',
template:'#appTemplate',
regions: {
header : '#header',
content : '#content',
footer : '#footer'
},
onRender : function () {
this.removeRegion("header", "#header"); //i am removing header alone here.
}
});
here is my controller.js
socialApp.loginController = Marionette.Controller.extend({
_initialize:function(){
this.loginView = new loginView({model:new loginModel});
this.layout.onRender(); //calling onRender from here...
this.layout.content.show(this.loginView);
}
});
But it's all not working. any one help me the correct way please?
You should never call methods that are prefixed with on manually. Those are there for your code to react to given events, in this case that the view’s render method was invoked.
I would suggest that you instead of trying to remove and then later re-add regions, you create two different layouts. Then when your router hits the login route, you render LoginLayout into your App’s root region, and for other routes, the ‘normal’ layout. Here’s how I solved something similar:
app.js:
var App = new Marionette.Application;
App.addRegions({ root: '#acme' });
// Instantiate User model
App.addInitializer(function()
{
this.user = new UserModel;
});
// Render App layout
App.addInitializer(function()
{
this.layout = this.user.get('id') ? new ContentLayoutView({ identifier: 'content' }) : new UserLayoutView({ identifier: 'user' });
this.root.show(this.layout);
// And let the routers decide what goes in the content region of each layout
this.router = {
content: new ContentRouter,
user: new UserRouter
};
});
layout/content.js
var ContentLayout = Marionette.LayoutView.extend(
{
identifier: 'content',
template: ContentLayoutTemplate,
regions: {
content: '[data-region="content"]',
panelLeft: '[data-region="panel-left"]',
panelRight: '[data-region="panel-right"]'
},
initialize: function()
{
this.content.once('show', function(view)
{
this.panelLeft.show(new PanelLeftView);
this.panelRight.show(new PanelRightView);
}.bind(this));
}
});
layout/user.js
var UserLayout = Marionette.LayoutView.extend(
{
identifier: 'user',
template: UserLayoutTemplate,
regions: {
content: '[data-region="content"]'
}
});
router/content.js
var ContentRouter = Marionette.AppRouter.extend(
{
routes: {
'(/)': '...'
},
createLayout: function(callback)
{
if(App.root.currentView.options.identifier != 'content')
{
var layout = new ContentLayoutView({ identifier: 'content' });
this.region = layout.content;
this.listenTo(layout, 'show', callback);
App.root.show(layout);
}
else
{
this.region = App.root.currentView.content;
callback();
}
},
execute: function(callback, args)
{
if(App.user.get('id'))
{
this.createLayout(function()
{
callback.apply(this, args);
}.bind(this));
}
else
App.router.user.navigate('login', true);
}
});
router/user.js
var UserRouter = Marionette.AppRouter.extend(
{
routes: {
'login(/)': 'showLogin',
'logout(/)': 'showLogout'
},
createLayout: function(callback)
{
if(App.root.currentView.options.identifier != 'user')
{
var layout = new UserLayoutView({ identifier: 'user' });
this.region = layout.content;
this.listenTo(layout, 'show', callback);
App.root.show(layout);
}
else
{
this.region = App.root.currentView.content;
callback();
}
},
execute: function(callback, args)
{
this.createLayout(function()
{
callback.apply(this, args);
}.bind(this));
},
showLogin: function()
{
var LoginView = require('view/detail/login');
this.region.show(new LoginView);
},
showLogout: function()
{
var LogoutView = require('view/detail/logout');
this.region.show(new LogoutView);
}
});

After closing the modal dialog refresh the base view

suggestion and code sample
I am new to Backbone marionette, I have a view ("JoinCommunityNonmemberWidgetview.js") which opens a modal dialog ("JoinCommunityDetailWidgetview.js").On closing of the dialog ( I want the view JoinCommunityNonmemberWidgetview.js") to be refreshed again by calling a specific function "submitsuccess" of the view JoinCommunityNonmemberWidgetview.js.
How can I achieve it.
The code for the modal is as below:
define(
[
"grads",
"views/base/forms/BaseFormLayout",
"models/MembershipRequestModel",
"require.text!templates/communitypagewidget/JoinCommunityWidgetDetailTemplate.htm",
],
function (grads, BaseFormLayout, MembershipRequestModel, JoinCommunityWidgetDetailTemplate) {
// Create custom bindings for edit form
var MemberDetailbindings = {
'[name="firstname"]': 'FirstName',
'[name="lastname"]': 'LastName',
'[name="organization"]': 'InstitutionName',
'[name="email"]': 'Email'
};
var Detailview = BaseFormLayout.extend({
formViewOptions: {
template: JoinCommunityWidgetDetailTemplate,
bindings: MemberDetailbindings,
labels: {
'InstitutionName': "Organization"
},
validation: {
'Email': function (value) {
var emailconf = this.attributes.conf;
if (value != emailconf) {
return 'Email message and Confirm email meassage should match';
}
}
}
},
editViewOptions: {
viewEvents: {
"after:render": function () {
var self = this;
var btn = this.$el.find('#buttonSubmit');
$j(btn).button();
}
}
},
showToolbar: false,
editMode: true,
events: {
"click [data-name='buttonSubmit']": "handleSubmitButton"
},
beforeInitialize: function (options) {
this.model = new MembershipRequestModel({ CommunityId: this.options.communityId, MembershipRequestStatusTypeId: 1, RequestDate: new Date() });
},
onRender: function () {
BaseFormLayout.prototype.onRender.call(this)
},
handleSubmitButton: function (event) {
this.hideErrors();
// this.model.set({ conf: 'conf' });
this.model.set({ conf: this.$el.find('#confirmemail-textbox').val() });
//this.form.currentView.save();
//console.log(this.form);
this.model.save({}, {
success: this.saveSuccess.bind(this),
error: this.saveError.bind(this),
wait: true
});
},
saveSuccess: function (model, response) {
var mesg = 'You have submitted a request to join this community.';
$j('<div>').html(mesg).dialog({
title: 'Success',
buttons: {
OK: function () {
$j(this).dialog('close');
}
}
});
grads.modal.close();
},
saveError: function (model, response) {
var msg = 'There was a problem. The request could not be processed.Please try again.';
$j('<div>').html(msg).dialog({
title: 'Error',
buttons: {
OK: function () {
$j(this).dialog('close');
}
}
});
}
});
return Detailview;
}
);
I would use Marionette's event framework.
Take a look at: https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.commands.md
Specifically, you need to:
1) Create a marionette application :
App = new Marionette.Application();
2) Use the application to set up event handlers
//Should be somewhere you can perform the logic you are after
App.commands.setHandler('refresh');
3) Fire a 'command' and let marionette route the event
App.execute('refresh');

KendoUI MVVM validation using Datasource Model validation rules

Just a little hack for validating against a kendo.data.Model
So instead of adding the HTML5 required attribute to each input field manually
this little hack gets all the validation rules that you defined in your Model and
add them as attributes to the appropriate field. Not fully tested just a quick hack. According to Kendo the validation rules don't get processed if you are using MVVM, but they do if for example you bind the Dataource directly to a grid.
Code:
I just put this code in a file called definevalidation.js
function getValidationAttributesFromModel(myFields) {
var myValidatedFields = [];
var obj = null;
$.each(myFields, function(fieldName) {
if (this.validation) {
var obj = {
fieldName : fieldName,
validation : this.validation
};
myValidatedFields.push(obj);
}
});
addValidationAttributes(myValidatedFields);
}
function addValidationAttributes(myValidatedFields) {
$.each(myValidatedFields, function(index) {
$('#' + this.fieldName).attr(this.validation);
});
}
Usage:
If ParentDS is your datasource then in your form code just use
getValidationAttributesFromModel(ParentDS.options.schema.model.fields)
Sample Model:
mydatamodel = kendo.data.Model.define({
id : "__KEY",
fields : {
__KEY : {
type : "string"
},
__STAMP : {
type : "number"
},
ID : {
editable : false,
nullable : true
},
firstName : {
type : "string",
validation : {
required : true
}
},
middleName : {
type : "string"
},
lastName : {
type : "string"
}
}
});

Resources