Binding and relationships in OpenUI5 - javascript

Currently, I am trying to build an interface in OpenUI5, which is supposed to allow managing relationships. The whole application connects to the backend via oData.
Consider the following example: Two entities, "Group" and "Person". Each Group may consist of a number of Persons ("members"). What I'd like to do is to list all the Groups in a table - and for each groups members, I'd like to present a MultiComboBox to select the Persons associated with the group, like so:
Setting up the views is easy, but I have some trouble regarding the bindings. Binding a collection (like "Groups") to a table and binding properties (like "name") to an item is no problem of course, but I have no clue how to bind a collection - which is a child of another collection - to a nested list so to speak.
I don't even know if it is possible at all, especially since I want not only the Persons currently affiliated with a group to show up in the combo box, but all others as well to be able to select them. And of course, I want changes made in the interface to apply to the model as well...
Any hint towards a way to achieve the described functionality is much appreciated!

Two different models are binded to the Table..
YOu can have Groups and Members as entities with navigation property as members
you can play around here
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
<title>Mobile App in 23 Seconds Example</title>
<script src="https://sapui5.netweaver.ondemand.com/resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.m"
data-sap-ui-theme="sap_bluecrystal"></script>
<!-- only load the mobile lib "sap.m" and the Blue Crystal theme -->
<script type="text/javascript">
var sampleData = {
"Groups": [
{
"GroupId": "D1",
"GroupName": "Developers",
"Members": []
},
{
"GroupId": "D2",
"GroupName": "GreenDay",
"Members": []
},
{
"GroupId": "D3",
"GroupName": "BackStreet Boys",
"Members": []
},
{
"GroupId": "D4",
"GroupName": "Managers",
"Members": []
}
]
};
var oModel = new sap.ui.model.json.JSONModel(sampleData);
var aData = [
{
key: "A",
text: "John"
},
{
key: "B",
text: "Sachin"
},
{
key: "C",
text: "Dravid"
},
{
key: "D",
text: "David"
},
{
key: "E",
text: "Sunil"
},
{
key: "F",
text: "Ronald"
},
{
key: "G",
text: "Albert"
}
];
var oMulti = new sap.m.MultiComboBox({
selectionChange: function (oEvent) {
//change your group data?
}
});
oMulti.setModel(new sap.ui.model.json.JSONModel(aData));
var oTemplate = new sap.ui.core.Item({
key: "{key}",
text: "{text}",
customData: new sap.ui.core.CustomData({
key: "{GroupId}",
value: "{GroupName}"
})
});
oMulti.bindItems("/", oTemplate);
//Build Table
var oTable = new sap.m.Table({
columns: [
new sap.m.Column({
width: "150px",
header: new sap.m.Label({
text: "Group Name"
})
}),
new sap.m.Column({
header: new sap.m.Label({
text: "Members"
})
})
]
}).placeAt("content");
var oTemplate = new sap.m.ColumnListItem({
cells: [
new sap.m.Label({
text: "{GroupName}"
}),
oMulti
],
press: function (oEvent) {
alert(oEvent.getSource().getBindingContext());
}
});
oTable.setModel(oModel);
oTable.bindItems("/Groups", oTemplate);
</script>
</head>
<body class="sapUiBody">
<div id="content"></div>
</body>
</html>

Related

How to make dojo treeGrid categorized by two columns?

I have a simple dojo treeGrid that is categorized just by first column. But how to make it categorized/collapsible by second as well? Note the treeGrid has totals shown in each category. Also, is there a way to move totals to the category level but not to the bottom?
var layout = [
{ cells: [
[ {field: "year", name: "Year"},
{field: "childItems",
children: [ { field: "unid", name: "unid", hidden: true},
{ field: "geography", name: "Geography"},
{ field: "country", name: "Coungtry"},
{ field: "status", name: "Status"},
{ field: "credit", name: "Credit"},
{ field: "debit", name: "Debit"}
],
aggregate: "sum"
}
]] } ]
var jsonStore = new dojo.data.ItemFileWriteStore({ url: <...............>});
var grid = new dojox.grid.TreeGrid({
structure: layout,
store: jsonStore,
query: {type: 'year'},
queryOptions: {deep: true},
rowSelector: true,
openAtLevels: [false],
autoWidth: true,
autoHeight: true
},
dojo.byId("treeGrid"));
grid.startup();
dojo.connect(window, "onresize", grid, "resize");
sample JSON store:
{
"identifier": "id",
"label": "name",
"items": [
{
"id": "2018",
"type": "year",
"year": "2018",
"childItems": [
{
"id": "id0",
"geography": "Asia Pacific",
"country": "Australia",
"programname": "Program 1",
"totalPlanned": 0,
"totalForecasted": 0
},
{
.....
}
]
},
{
.....
}
]
}
You can find completely working example over here:
Now, let me try to explain it:
Data
First of all to support multiple levels in the grid you must have your data in the same format. For tree with n levels, you need to have n-1 level grouping in your data itself.
For example, JSON object below have 2 levels of grouping (year, geography) to support tree with 3 levels (root, parent, and child).
{
"identifier":"id",
"label":"name",
"items":[
{
"id":"2018",
"type":"year",
"year":"2018",
"geography":[
{
"id":"id1",
"geography":"Asia Pacific",
"childItems":[
{
"id":"ci1",
"country":"Australia",
"programname":"Program 1",
"credit":100,
"debit":50
}
]
}
]
}
]
}
Layout
To render a tree with n-levels you have to make sure layout of the tree is properly configured with same nesting as your data. To support data structure from JSON object above you need to set layout to:
[
{
cells:
[
[
{ field:"year", name:"Year" },
{
field:"geography",
children:
[
{ field:"geography", name:"Geography" },
{
field:"childItems",
children:[
{ field:"unid", name:"unid", hidden:true },
{ field:"country", name:"Country" },
{ field:"programname", name:"Program" },
{ field:"credit", name:"Credit" },
{ field:"debit", name:"Debit" }
],
aggregate:"sum",
},
]
}
]
]
}
]
You can see that, for each child level(s) you have to add a group (as I would like to call it) field and set first field within that group to your actual group field.
I hope this example will clear your doubt.
PS: In the jsfiddle version I have used formatters just to hide aggregate values for string fields.

AngularJS: get object property in array by matching a different property?

I have an array of products, displayed in a table with an AngularJS ng-repeat.
The products are an array of objects returned from a Wordpress REST API call, and each object has a "category", which returns as a number.
Example: { "name": "Foo", "cat": 12 }
I can't simply bind to the "cat" property, since it displays "12" and I want to display the category label instead.
I can query for the list of all categories, and get an array like so:
[
{ label: 'Customer Engagement Solutions', id: 2 },
{ label: 'Small and Medium Business', id: 13 },
{ label: 'Customer Information Management', id: 4 },
{ label: 'eCommerce', id: 25 },
{ label: 'Location Intelligence', id: 16 },
{ label: 'Enterprise', id: 12 }
]
My product above, "Foo" should display "Enterprise", which is 12.
I know I can bind to a function, as in {{ctrl.getCat(product)}} but I'm not sure how to do the matching of the ID in the product to the one in the category array, and return the category label.
This is trivial to do in actual Wordpress PHP as they provide a function for this very task.
Use Array#find() or even more performant is create a hashmap of the category labels using id as property keys
Using find()
ctrl.getCat = function(product){
let cat = categories.find(e => e.id === product.cat)
return cat ? cat.label : 'Unknown';
}
Or as hashmap:
ctrl.catLabels = categories.reduce((a,c) => { a[c.id] = c.label; return a;},{})
Then in view:
{{ctrl.catLabels[product.cat]}}
The easiest way would be to create a new array of products that already maps the categories. When you initialize the controller with the products and categories, create a new array the maps it.
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
const _categories = [
{ label: 'Customer Engagement Solutions', id: 2 },
{ label: 'Small and Medium Business', id: 13 },
{ label: 'Customer Information Management', id: 4 },
{ label: 'eCommerce', id: 25 },
{ label: 'Location Intelligence', id: 16 },
{ label: 'Enterprise', id: 12 }
];
const _products = [
{ "name": "Foo", "cat": 12 },
{ "name": "Bar", "cat": 16 },
{ "name": "Foo Bar", "cat": 12}
]
let categoryMap = {}
_categories.forEach( (category)=>{
categoryMap[category.id] = category.label;
})
this.products = _products.map( (product)=>{
return {
"name": product.name,
"category": categoryMap[product.cat]
}
})
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
</head>
<body ng-controller="MainCtrl as ctrl">
<div ng-repeat="product in ctrl.products">
<span>Name: {{product.name}}</span> <span>Category: {{product.category}}</span>
</div>
</body>
</html>

AngularJS TreeView From JSON Object

I am newbie in AngularJS. I need to create a TreeView Structure From JSON Object.
My Return JSON Object is looks like below.
var categoryTree = [{Name:'Item1', Childnodes : {}, id: 1},
{Name:'Item2', Childnodes : {
items = [
{Name:'Sub Item21', Childnodes : {}, id: 21}
{Name:'Sub Item22', Childnodes : {}, id: 22}
]
}, id: 2}];
Could you please help me to create a AngularJS Tree View.
Thanks in Advance.
You can create a Tree view using the Webix framework along with AngularJS.
https://github.com/TheAjinkya/webixTreeWithJava-
https://github.com/TheAjinkya/AngularWebixApplication
treedata = [{
id: "1",
value: "Book 1",
data: [{
id: "1.1",
value: "Part 1"
},
{
id: "1.2",
value: "Part 2"
}
]
},
{
id: "2",
value: "Book 2",
data: [{
id: "2.1",
value: "Part 1"
}]
}
];
tree = new webix.ui({
view: "tree"
});
tree.parse(treedata)
<script src="https://cdn.webix.com/edge/webix.js"></script>
<link href="https://cdn.webix.com/edge/webix.css" rel="stylesheet" />
Please use some sort of tree view module. They can make your life much easier. The only thing is that you need to re-format your data structure to the tree module style. You can write a service and do all re-formatting inside a service.
Some tree view module and plugin:
http://ngmodules.org/modules/angular.treeview
https://angular-ui-tree.github.io/angular-ui-tree/#/basic-example

Kendo Grid sometimes renders only title or data

I have a pretty simple Kendo Grid that displays a list of data with titles and is conditionally editable on a field. This is rendered and attached to the DOM using JQuery in a function that is called in the "show" action of a Kendo View.
The issue is that either the data does not render or the grid column headers don't render every time I load the page. It's always one or the other, the only time it renders properly is if I refire the function that attaches it as I occasionally do when the state of the page changes.
Here's where I attach it to the page:
form.find("#approvals").kendoGrid({
columns: [
{ title: "Service", field: "PartDescription" },
{ title: "Component", field: "Component", width: "250px" },
{ title: "Status Last Modified", width: "250px", template: "#= kendo.toString(StatusModifiedDate, 'g') #", },
{ title: "Status", field: "Status", width: "135px", editor: statusDropDownEditor }
],
editable: modifyState,
edit: function (e) {
if (e.container.find("input").attr("name") !== "Status") {
this.closeCell();
}
}
});
This comes from the function that is fired when the Kendo View is shown.
The issue is that either the data does not render or the grid column
headers don't render every time I load the page.
Without knowing what "form" is in your js code, try using this to make sure it loads at the 'correct' time. Please feel free to tinker the gridData variable to match your code and preg_replace the fields for your fields.
<!DOCTYPE html>
<html>
<head>
<script src="https://kendo.cdn.telerik.com/2017.1.118/js/jquery.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2017.1.118/js/kendo.all.min.js"></script>
<meta charset="utf-8"/>
<title>Kendo UI Snippet</title>
</head>
<body id="theBod">
<div id="approvals"></div>
<script type="text/javascript">
$(function () { // the dom is ready for jquery parsing
var gridData = [{
"Name": "daya",
"Role": "Developer",
"Dept": "Dev",
"Date": "\/Date(836438400000)\/",
"Balance": 23
}, {
"Name": "siva",
"Role": "Developer",
"Dept": "Dev",
"Date": "\/Date(836438400000)\/",
"Balance": 23
}, {
"Name": "sivadaya",
"Role": "Developer",
"Dept": "Dev",
"Date": "\/Date(836438400000)\/",
"Balance": 23
}, {
"Name": "dayasiva",
"Role": "Developer",
"Dept": "Dev",
"Date": "\/Date(836438400000)\/",
"Balance": 23
}];
var form = $("#theBod");
var foundForm = $(form).find("#approvals");
if (typeof (foundForm) != "undefined") {
// process grid component
var grid = $(foundForm).kendoGrid({
dataSource: {
data: gridData,
schema: {
model: {
fields: {
Name: { type: "string" },
Role: { type: "string" }
}
}
},
pageSize: 10,
},
editable: true,
sortable: true,
columns: [
{
field: "Name",
title: "Name",
},
{
field: "Role",
title: "TheRole"
}
]
});
} else {
alert('no dom element located');
}
});
</script>
</body>
</html>
I have added a jsBin file for you.
The jsBin was not saved correctly, apologies.

Kendo Grid: Group by first element in a list

So I'm working with a Kendo Grid and how it's headers are grouped. One option that I have working currently is for the Grid to grab my list and sort group by checking every element in that list. So I get something like:
->Roles:
->Roles: Tester, Manager, Team Lead
->Roles: Tester
->Roles: CEO, Tester
->Roles: Team Lead, CEO
(you get the idea). This is because "Roles" in my database model are in a list (since a person can have many roles) and the Kendo Grid is comparing every element in that list. However, I want it to group by just the first element in each person's list so I instead get something like:
->Roles: Tester
->Roles: Manager
->Roles: Team Lead
->Roles:
->Roles: CEO
etc. Does anyone know how to do this? Currently I am doing
group: {
field: "RoleName",
aggregates: [
{ field: "ResourceName", aggregate: "count" },
{ field: "OrganizationName", aggregate: "count" }
]
},
And I assume that I want to be doing something more along the lines of:
group: {
field: "RoleName.get(0)",
aggregates: [
{ field: "ResourceName", aggregate: "count" },
{ field: "OrganizationName", aggregate: "count" }
]
},
However, I'm not familiar enough with Kendo Grid to know the syntax to do this correctly. Thanks in advance for all help!
Edit: I should add that because many of the people that will be using this still need IE8 support, I am using Kendo Grid imports from /2012.2.710 instead of the latest update
*Edit My Answer assumes the user loads the data outside the function and doesn't hard code in the data.
Try using the parse function in schema,
I'll just add to what you should have in your project already, for example:
$('.grid').kendoGrid({
dataSource: {
schema: {
parse: function(data) {
for (var i = 0; i < data.length; i++) {
data[i].firstWord = data[i].name.split(' ')[0];
}
return data;
}
}
group: {
field: "firstWord"
}
},
columns: [{
field: "name"
}, {
field: "firstWord",
hidden: true,
groupHeaderTemplate: "#=value#"
}]
});
This is just a fix over Ryan Hoyle answer's example:
var grid = $('#grid').kendoGrid({
dataSource: {
data: [{
name: 'Hello world'
}, {
name: 'Hello John Doe'
}, {
name: 'Hello Jane Doe'
}, {
name: 'Bye Jane Doe'
}, {
name: 'Bye World'
}],
schema: {
parse: function(data) {
data.forEach(d => d.firstWord = d.name.split(' ')[0]);
return data;
}
},
group: {
field: "firstWord"
}
},
columns: [{
field: "name"
}, {
field: "firstWord",
hidden: true,
groupHeaderTemplate: "#=value#"
}]
}).data().kendoGrid;
<link href="http://kendo.cdn.telerik.com/2016.2.607/styles/kendo.common.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2016.2.607/js/kendo.all.min.js"></script>
<div id="grid"></div>

Categories