Unable to access control, created in JSView, from controller with View byId - sapui5

I am trying to display a VizFrame and my data are in a simple JSON format.
Both my view and controller are in JS. (I will start writing my view in XML going forward) because I see that is the way to go.
I get a blank page with the error: "setDataset of undefined". What am I missing?
My view code is this.
createContent: function(oController) {
var oSubHeader = new sap.m.Bar({
contentLeft: [
new sap.m.Button({
icon: "sap-icon://nav-back",
press: [oController.onNavBack, oController]
})
],
contentMiddle: [
new sap.m.Label({
text: "{i18n>app_subhead_2}"
})
]
});
var oVizFrame = new sap.viz.ui5.controls.VizFrame("VizFrameId", {
width: "100%",
height: "400px",
vizType: "line"
});
var oPage = new sap.m.Page({
title: "UI5 Assignment App",
showSubHeader: true,
subHeader: oSubHeader,
content: [oVizFrame]
});
return oPage;
}
My corresponding controller is
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/UIComponent",
"sap/ui/core/routing/History",
"sap/viz/ui5/controls/VizFrame",
"sap/viz/ui5/data/FlattenedDataset"
], function (Controller, UIComponent, History, VizFrame, FlattenedDataset) {
"use strict";
return Controller.extend("Project_Tile_learning.Divya_tile_Project.controller.ProductDetailPage", {
onNavBack: function () {
var oHistory = History.getInstance();
var sPreviousHash = oHistory.getPreviousHash();
if (sPreviousHash !== undefined) {
window.history.go(-1);
} else {
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("homepage", true);
}
},
onInit: function () {
var sampleDatajson = new sap.ui.model.json.JSONModel("json/PA.json");
var oVizFrame = this.getView().byId("VizFrameId");
var oDataset = new sap.viz.ui5.data.FlattenedDataset({
dimensions: [{
name: "Year",
value: "{Year}"
}],
measures: [{
name: "Supplier",
value: "{Supplier}"
}, {
name: "Liquor",
value: "{Liquor}"
}, {
name: "Quantity",
value: "{Quantity}"
}],
data: {
path: "/items"
}
});
oVizFrame.setDataset(oDataset);
oVizFrame.setModel(sampleDatajson);
var oFeedValueAxis = new sap.viz.ui5.controls.common.feeds.FeedItem({
"uid": "valueAxis",
"type": "Measure",
"values": ["Supplier"]
});
var oFeedValueAxis1 = new sap.viz.ui5.controls.common.feeds.FeedItem({
"uid": "valueAxis",
"type": "Measure",
"values": ["Liquor"]
});
var oFeedValueAxis2 = new sap.viz.ui5.controls.common.feeds.FeedItem({
"uid": "valueAxis",
"type": "Measure",
"values": ["Quantity"]
});
var oFeedCategoryAxis = new sap.viz.ui5.controls.common.feeds.FeedItem({
"uid": "categoryAxis",
"type": "Dimension",
"values": ["Year"]
});
oVizFrame.addFeed(oFeedValueAxis);
oVizFrame.addFeed(oFeedValueAxis1);
oVizFrame.addFeed(oFeedValueAxis2);
oVizFrame.addFeed(oFeedCategoryAxis);
}
});
});

Update: JS View is deprecated since UI5 v1.90. Use Typed View instead.
When creating a control in JS view definition, always use this.createId("myControl").
From the doc:
If you want to define IDs for controls inside a JSView to guarantee their uniqueness [...], you cannot give hardcoded IDs, but have to give the view the opportunity to add its own instance ID as a prefix. This is done by using the View.createId(...) method.
For the example above, this is done as follows:
new sap.viz.ui5.controls.VizFrame(this.createId("VizFrameId"), { /*...*/ });
Then in the controller, myView.byId tries to access the control with view's own ID as a prefix, which will succeed this time since the control has an ID with the view ID as a prefix.

Related

SAPUI5 Planning Calendar need appointments in one line

I'm trying to use the PlanningCalender from SAPUI5. However, I have a problem when I switch to the week view. Here appointments that are close together are written in a new line. But I don't want this behavior. All appointments should be written one after the other, even if I can then no longer read the content of the appointments.
It seems like there is a minimum width for appointments. But I can't find a way to change this appointment width.
Does anyone have an idea how I can get the appointments one after the other?
Plunker Example
sap.ui.define([
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel',
'sap/m/Dialog',
'sap/m/Button'
],
function(Controller, JSONModel,Dialog, Button) {
"use strict";
var PageController = Controller.extend("sample1.View1", {
onInit: function () {
// create model
var oModel = new JSONModel();
oModel.setData({
startDate: new Date("2015", "11", "15", "8", "0"),
people: [
{
pic: "sap-icon://employee",
name: "John Doe",
role: "team member",
appointments: [
{
start: new Date("2015", "11", "15", "08", "30"),
end: new Date("2015", "11", "15", "10", "30"),
title: "Meeting",
type: "Type02",
tentative: false
},
{
start: new Date("2015", "11", "15", "10", "30"),
end: new Date("2015", "11", "15", "12", "0"),
title: "Team meeting",
info: "room 1",
type: "Type01",
pic: "sap-icon://sap-ui5",
tentative: false
},
{
start: new Date("2015", "11", "15", "12", "00"),
end: new Date("2015", "11", "15", "13", "30"),
title: "Lunch",
type: "Type03",
tentative: true
}
]
}
]
});
this.getView().setModel(oModel);
},
handleAppointmentSelect: function (oEvent) {
var oAppointment = oEvent.getParameter("appointment");
if (oAppointment) {
alert("Appointment selected: " + oAppointment.getTitle());
}else {
var aAppointments = oEvent.getParameter("appointments");
var sValue = aAppointments.length + " Appointments selected";
alert(sValue);
}
},
handleIntervalSelect:function(oEvent){
var dialogData = {
newEntry: {
start: oEvent.getParameter("startDate"),
end: oEvent.getParameter("endDate"),
title: "",
info: "",
type: "Type01",
pic: "sap-icon://sap-ui5",
tentative: false
},
people: this.getView().getModel().getProperty("/people").map(function(p,i){ return { name: p.name, index: i, selected: true }; }) //A List of all people. All selected by default.
};
var dialogModel = new JSONModel(dialogData);
var that = this;
var planningDialog = new Dialog({
title:"Add Appointment",
content: sap.ui.xmlview({viewName:"sample1.AppointmentDialog"}).setModel(dialogModel),
leftButton: new Button({
text: "Cancel",
press: function(){
planningDialog.close();
planningDialog.destroy();
}}),
rightButton: new Button({
text: "Save",
type: "Accept",
press: function(){
planningDialog.close();
that.addAppointment(dialogData);
}}),
});
planningDialog.open();
},
addAppointment:function(data){
var model = this.getView().getModel();
var peopleList = model.getProperty("/people");
data.people
.filter(function(p){return p.selected;})
.forEach(function(p){
peopleList[p.index].appointments.push(data.newEntry);
});
model.setProperty("/people",peopleList); //Updates Bindings
}
});
return PageController;
});
setBuiltInViews
Sets a new value for property builtInViews.
Defines the list of predefined views as an array. The views should be specified by their keys.
The default predefined views and their keys are available at sap.m.PlanningCalendarBuiltInView.
Note: If set, all specified views will be displayed along with any custom views (if available). If not set and no custom views are available, all default views will be displayed. If not set and there are any custom views available, only the custom views will be displayed.
When called with a value of null or undefined, the default value of the property will be restored.
Default value is [].
What you are looking for is somehow tweak -- sap.m.PlanningCalendarBuiltInView.Week.
Haven't worked on it, will look for the solution! All the best!

SAPUI5 formatter parameter value is always null

I am trying to add an icon to my table column. The icon should be selected depending on the value. Therefore I implemented some formatter function which is based in the model/formatter.js file.
Here is the code I try to add the the table column:
new sap.ui.layout.VerticalLayout({
content: [
new sap.m.Label({text:"{Items>Status}"}),
new sap.ui.core.Icon({
src: {
parts: [
"Items>Status"
],
formatter: Formatter.formatStatusIcon
},
size: "1rem",
color: {
parts: [
"Items>Status"
],
formatter: Formatter.formatStatusIconColor
}
})
]
})
The label does display the correct value. The icon is not displayed. The formatter function has as input value always null even though the values exist and are not null. I am using SAPUI5 version 1.61.2. I already tried different syntaxes of the parts property but none of them did work. I also tried adding some static value instead of "Items>Status" for testing purpose but the input in the formatter function is still null.
Has anyone an idea why the input of the formatter function is always null?
Based on the your input, I have understood that you have a JS view and your are changing the Icon and its color based on the status
View.js
var oTable = new sap.m.Table("idPrdList", {
headerText : "List of Products",
headerDesign : sap.m.ListHeaderDesign.Standard,
mode : sap.m.ListMode.None,
includeItemInSelection : false,
});
var col1 = new sap.m.Column({header: new sap.m.Label({text:"Product Name"})});
oTable.addColumn(col1);
var col2 = new sap.m.Column({header: new sap.m.Label({text:"Description"})});
oTable.addColumn(col2);
var col3 = new sap.m.Column({header: new sap.m.Label({text:"Price"})});
oTable.addColumn(col3);
controller.js
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData({
'items': [
{
'ProductID': "sdf",
'ProductName': "asdf",
"Status": "1"
},
{
'ProductID': "ss",
'ProductName': "asf",
"Status": "1"
},
{
'ProductID': "fff",
'ProductName': "asdf",
"Status": "2"
},
{
'ProductID': "fas",
'ProductName': "asdf",
"Status": "1"
},
{
'ProductID': "asdfa",
'ProductName': "asdfwer",
"Status": "2"
}]
});
sap.ui.getCore().setModel(oModel, "tableData");
var oTable = sap.ui.getCore().byId("idPrdList");
var colItems = new sap.m.ColumnListItem("colItems", {
type: "Active"
});
var txtNAME = new sap.m.Text({
text: "{tableData>ProductID}"
});
colItems.addCell(txtNAME);
var txtNAME2 = new sap.m.Text({
text: "{tableData>ProductName}"
});
colItems.addCell(txtNAME2);
var txtNAME3 = new sap.ui.layout.VerticalLayout({
content: [
new sap.m.Label({
text: "{tableData>Status}"
}),
new sap.ui.core.Icon({
src: {
parts: ["tableData>Status"],
formatter: assets.util.mFormatter.formatStatusIcon
},
size: "1rem",
color: {
parts: ["tableData>Status"],
formatter: assets.util.mFormatter.formatStatusIconColor
}
})
]
})
colItems.addCell(txtNAME3);
oTable.bindAggregation("items", "tableData>/items", colItems);
oTable.setModel(oModel, "tableData");
Formatter.js
jQuery.sap.declare("assets.util.mFormatter");
assets.util.mFormatter = {
formatStatusIcon: function(Status) {
return (Status === "2" ? "ICONPath1" : "ICONPath2");
},
formatStatusIconColor: function(Status) {
return (Status === "2" ? "Color1" : "Color2");
},
};
Output
Your syntax is wrong I think. Remove that parts stuff.
Try this:
src="{path: 'invoice>Status',
formatter: '.Formatter.statusText'}
Try this syntax below :
new sap.ui.layout.VerticalLayout({
content: [
new sap.m.Label({text:"{Items>Status}"}),
new sap.ui.core.Icon({
src: {
parts: [
{path: 'Items>Status'}
],
formatter: '.Formatter.formatStatusIcon'
},
size: "1rem",
color: {
parts: [
"Items>Status"
],
formatter: Formatter.formatStatusIconColor
}
})
]
})

All appointments have a different row (sap.m.PlanningCalendar)

I am trying to port my old application with "sap.me.OverlapCalendar" to the new "sap.m.PlanningCalendar", I want to show appointments just for one person. I found a difference in the way the appointments display.
The template I use is:
var oTemplateRow = new sap.m.PlanningCalendarRow("RowTemplate", {
appointments:[
new sap.ui.unified.CalendarAppointment({
startDate: {
path: 'CalendarModel>DateFrom',
formatter: util.Formatter.toStartDate
},
endDate: {
path: 'CalendarModel>DateTo',
formatter: util.Formatter.toEndDate
},
title: "{CalendarModel>CardName} - {CalendarModel>ProjectName}",
text: "Gewerkte uren: {CalendarModel>WorkedHours}",
type: "Type04",
tentative: false,
key: "{CalendarModel>ReportID}"
})]
});
Which is bound to the Calendar control with:
bindAggregation("rows", "CalendarModel>/Items/", oTemplateRow);
The data is showing in the calendar but the way it shows is different.
Old calendar: http://imgur.com/3glZRtT
New calendar: http://imgur.com/snnsWVE
What should I do to get the same output?
You have to change the model: for example, at the root of the model you create an array corresponding to rows of the calendar, and each row should contain an array of appointments.
A sample json file can look like this:
{
"items": [{
"title": "Item1",
"appointments": [{
"text": "appointment1",
"start": "2017-02-17T09:30:00",
"end": "2017-02-17T13:00:00"
}, {
"text": "appointment2",
"start": "2017-02-17T09:45:00",
"end": "2017-02-17T13:10:00"
}]
}, {
"title": "Item2",
"appointments": [{
"text": "appointment3",
"start": "2017-02-17T10:30:00",
"end": "2017-02-17T14:00:00"
}, {
"text": "appointment4",
"start": "2017-02-17T10:45:00",
"end": "2017-02-17T14:10:00"
}]
}]
}
"items" is an array of calendar rows, and each item contains array of appointments. The binding of the control should be more complex. I used such a file a base for JSON model and the controller code looks like this:
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function(Controller) {
"use strict";
return Controller.extend("QuickStartApplication.controller.View1", {
onInit: function() {
var oCale = this.getView().byId("PC1");
var oModel = this.getOwnerComponent().getModel("CalendarModel");
this.getView().setModel(oModel, "CalendarModel");
var oTemplateRow = new sap.m.PlanningCalendarRow("RowTemplate", { title: "{CalendarModel>title}" });
oTemplateRow.bindAggregation("appointments", {
path: "CalendarModel>appointments",
template: new sap.ui.unified.CalendarAppointment({
title: "{CalendarModel>text}",
startDate: {
path: "CalendarModel>start",
formatter: this.toDate
},
endDate: {
path: "CalendarModel>end",
formatter: this.toDate
}
}),
templateShareable: true
});
oCale.bindAggregation("rows", {
path: "CalendarModel>/items",
template: oTemplateRow,
templateShareable: true
});
},
toDate: function(sValue) {
if (sValue) {
return new Date(sValue); //
}
}
});
});
Note that first you create a row template and then bind its "appointments" aggregation to the "appointments" property of "CalendarModel" model with template for CalendarAppointment creation. Then you create a binding for calendar rows referring to the row template.

SAPUI5 - sap.m.Table with factory functions not showing columns and items

I have a requirement wherein I have to populate columns and rows dynamically from oData. For test purpose I created the following JSON files for columns and rows.
column.json
{
"Columns": [
{ "column": "col1" },
{ "column": "col2" },
{ "column": "col3" }
]
}
row.json
{
"Rows": [
{ "col1": "abc",
"col2": "def",
"col3": "ghi"
},
{ "col1": "jkl",
"col2": "mno",
"col3": "pqr"
}
]
}
Here is my view
<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
controllerName="sam.test" xmlns:html="http://www.w3.org/1999/xhtml">
<Table id="ID"
columns="{path: 'Column>/Columns', factory: '.populateColumns'}"
items="{path: 'Row>/Rows', factory: '.populateItems'}">
</Table></core:View>
Note that in manifest file "Column" points to column.json and "Row" points to row.json file.
Here is my corresponding controller -
sap.ui.controller("sam.test", {
// onInit: function() {
// },
// onBeforeRendering: function() {
//
// },
// onAfterRendering: function() {
//
// },
// onExit: function() {
//
// }
populateItems: function(sId, oContext) {
var row = new sap.m.ColumnListItem(sId, {
type: "Active",
cell: [
new Text({
text: "{Column>col1}"
}),
new Text({
text: "{Column>col2}"
}),
new Text({
text: "{Column>col3}"
})
]
});
return row;
},
populateColumns: function(sId, oContext) {
var sColumnId = oContext.getObject().column;
return new sap.ui.table.Column({
id: sColumnId,
label: sColumnId,
template: sColumnId,
sortProperty: sColumnId,
filterProperty: sColumnId
});
}
});
This however is not working. It renders table with no column headers and no rows. When I bind rows directly to items aggregation of Table and also provide columns aggregation with same value it works.
Am I missing something? I am having tough time figuring this out. Any pointers will be appreciated
Thanks!
3 Mistakes which I found:
Wrong type of Column: new sap.ui.table.Column- The correct column type should be sap.m.Column since this is a sap.m.Table.
Wrong name of aggregation used for sap.m.ColumnListItem: The correct aggregation is cells and not cell ( typo).
Wrong model is bound to ColumnListItem: It should be Row>col1 and not Column>col1 as Row model stores the data.
Lets correct these mistakes and below is the working code:
populateItems: function(sId, oContext) {
var row = new sap.m.ColumnListItem(sId, {
type: "Active",
cells: [
new sap.m.Text({
text: "{Row>col1}"
}),
new sap.m.Text({
text: "{Row>col2}"
}),
new sap.m.Text({
text: "{Row>col3}"
})
]
});
return row;
},
populateColumns: function(sId, oContext) {
var sColumnId = oContext.getObject().column;
return new sap.m.Column({
header: new sap.m.Text({
text:'{Column>column}'
})
});
},
Let me know if this works.

How to navigate to another XML page when the user click on message popup button

View1.Controller.js
onClickRUSSIA: function() {
var dialog = new Dialog({
title: 'Default Message',`enter code here`
type: 'Message',
content: new Text({
text: 'Country : RUSSIA \n Contenent : ASIA \n language:RUSSIAN.'
}),
beginButton: new Button({
text: 'OK',
press: function() {
dialog.close();
}
}),
endButton: new Button({
text: 'More Info',
press: function() {
//this.getRouter().navTo("mohan");
var router = sap.ui.core.UIComponent.getRouterFor();
router.navTo("View2");
}
}),
afterClose: function() {
dialog.destroy();
}
});
dialog.open();
},
Component.js
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/Device",
"Test1/model/models"
], function(UIComponent, Device, models) {
"use strict";
return UIComponent.extend("Test1.Component", {
metadata: {
//rootView: "test1.webapp.view.App",
manifest: "json",
routing: {
config: {
viewType: "XML",
viewPath: "test1.webapp.view",
controlId: "rootControl",
controlAggregation: "pages",
//routerClass: "Test1.controller",
transition: "slide"
},
routes: [
{
pattern: "",
name: "default",
view: "view1"
}, {
pattern: "mohan",
name: "view2",
View: "view2"
}
]
// targets: {
// page1: {
// viewName: "View1",
// viewLevel: 0
// },
// page2: {
// viewName: "View2",
// viewLevel: 1
// }
// }
}
},
init: function() {
// call the base component's init function
UIComponent.prototype.init.apply(this, arguments);
jQuery.sap.require("sap.m.routing.RouteMatchedHandler");
jQuery.sap.require("sap.ui.core.routing.HashChanger");
sap.ui.core.UIComponent.prototype.init.apply(this, arguments);
this._router = this.getRouter();
// set the device model
this.setModel(models.createDeviceModel(), "device");
//initlialize the router
this._routeHandler = new sap.m.routing.RouteMatchedHandler(this._router);
this._router.initialize();
}
});
});
You will have to get the router for your controller/view. As this is not your controller inside endButton.press(), you have to use a helper variable that.
You have to give Router.navTo() the name of the route to navigate to. So it has to be view2 instead of View2.
var that = this;
var dialog = new Dialog({
...
endButton: new Button({
text: 'More Info',
press: function() {
var router = sap.ui.core.UIComponent.getRouterFor(that);
router.navTo("view2");
}
}),
...
this.getOwnerComponent().getTargets().display("page1");