I'm working on a SAPUI5 App containing a SplitApp with one MasterPage and many DeatilPages. I create a list of StandartListItems for the MasterPage, if I select one of them, I want to show the right DetailPage. But at this point I have no idea how to implement it.
Fill the list of the MasterPage:
var oMasterPage = sap.ui.getCore().byId("masterPage");
var masterContentList = sap.ui.getCore().byId("masterList");
masterContentList.bindItems({
path : "/inhaltList",
template : new sap.m.StandardListItem({
title: "{master}"
})
});
And for each MasterListItem I create a DetailPage and add it to the SplitApp:
var detailContentList = new sap.m.List({});
detailContentList.bindItems({
path : "/inhaltList",
sorter : new sap.ui.model.Sorter("name"),
template : new sap.m.CustomListItem({
content: [
new sap.m.VBox({
width : "80%",
displayInline : false,
direction: "Column",
items:[
new sap.ui.commons.TextView({text:"titel", design:sap.ui.commons.TextViewDesign.H2}),
//new sap.ui.commons.TextView({text:"{detail>titel}", design:sap.ui.commons.TextViewDesign.H2}),
//new sap.ui.commons.TextView({text:"{detail>content>text}", design:sap.ui.commons.TextViewDesign.Small})
new sap.ui.commons.TextView({text:"textetextetextetexttextexte", design:sap.ui.commons.TextViewDesign.Small})
]
})
]
})
});
var DetailPage = new sap.m.Page({
path : "/inhaltList",
title: "{master}",
content:[
detailContentList
]
});
splitApp.addDetailPage(DetailPage);
In the end, I have one MasterPage in the SplitApp and in one case 4 DetailPages. That is up to this point working.
Now, I want to make a relation from the MasterListItem to the right DetailPage, so that the right DetailPage is showing up, if I selct the MasterListItem for that.
Does anyone have an idea?
As I understand you have sap.m.StandardListItem with some items and you want to switch details while clicking on an item. Easiest way:
1. add press event to your item. controller is a controller, if you are doing it in a view.
press: [controller.pressItem, controller]
2.from pressItem, get your application and use to method.
var app = sap.ui.getCore().byId("splitApp");
app.to(id, "slide", data)
where id - is the id of your detail page and data is the payload you want to send to the page.
Notes:
1. Implementation through event bus will also work and would be better
Related
I've a table specifying the roles and actions, if I check in the role and press delete button, then I should get a dialog box indicating that specific role
If I click on add button, I should get a dialog box or message box with the list of few other roles and on clicking on that role, a rolename should be displayed that has to be added to the respective table
I've created the sap.m.Table and I'm binding the JSON data
Enclosed the Image of the UI:
I've tried with various methods and I'm enclosing my code
Here is the code..
I can delete the item from the table, but I should get a dialog/message box indicating that, the checkmarked role in the table has been deleted
<script>
function delete1()
{
var v = false;
$('input[type="checkbox"]:checked').each(function() {
v = true;
alert("Checked item in the table will be deleted from the table");
});
if (v == false)
{
alert("Please check the item to be deleted");
}
$('input[type="checkbox"]:checked').closest("tr").remove();
}
var oModel = new sap.ui.model.json.JSONModel("JSon/etc5.json");
// Load JSON in model
sap.ui.getCore().setModel(oModel,"model1");
//create table
//"cells"
var oRoles = new sap.m.Text({text: "{model1>Role}"});
var oAction = new sap.m.Button({text: "DETAILS",
type : sap.m.ButtonType.Emphasized,
});
// corresponding columns
var oColAbbr = new sap.m.Column({header: new sap.m.Text({text:"ROLES"}) });
var oColAct = new sap.m.Column({header: new sap.m.Text({text:"ACTION"}) });
// row template
var oRow = new sap.m.ColumnListItem();
oRow.addCell(oRoles).addCell(oAction);
// instantiating the table
var oTab = new sap.m.Table("app",{
inset : true,
headerText : "SOME DATA",
headerDesign : sap.m.ListHeaderDesign.Standard,
includeItemInSelection : false,
});
oTab.addColumn(oColAbbr).addColumn(oColAct);
oTab.bindItems("model1>/emp", oRow); //binding data to the tables
oTab.setMode(sap.m.ListMode.MultiSelect);
var oButton = new sap.m.Toolbar({
content: [
new sap.m.ToolbarSpacer(),
new sap.m.Button({
text : "ADD",
textAlign : "Center",
width : "10%",
type: sap.m.ButtonType.Emphasized,
press: function() {
// oCDialog2.open();
},
}),
new sap.m.Label({text:""}),
new sap.m.Button({
text : "DELETE",
textAlign : "Center",
width : "10%",
type: sap.m.ButtonType.Reject,
press: function() {
// oCDialog1.open();
delete1();
}
}),
]
});
//creating the icons
var iTab = new sap.m.IconTabBar({
items:[
new sap.m.IconTabFilter({
text: "HR",
icon: "sap-icon://group",
content:[oTab]
}),
]
});
var page = sap.m.Page({
content: [iTab,oButton],
showHeader : false,
enableScrolling : true,
});
var app = sap.m.App();
app.addPage(page);
app.placeAt("content");
</script>
It is probably easiest to use the Checkbox control and bind it's value to the same model as where the item lines come from (model1>/emp). In your delete method, you could then easily iterate through the emp array and test on the value representing the checkbox.
Whenever you delete an entry from the array, either UI5's MessageToast or MessageBox controls to show the message. Alerts may be blocked by "Check here to disable alerts from this website" functionality in some browsers.
You may also want to change the $.each to a $.grep instead. This loops through an array in pretty much the same way as $.each with one exception. If you return true from the callback, the element is retained. Otherwise, it is removed from the array.
Your code should look something like this:
items = this.getView().getModel("model1").getProperty("/emp");
items = $.grep(items, function (el, i) {
if (el.propertyBoundToCheckbox) {
MessageToast.show("Deleting entry: " + el.getName())
return false;
}
return true; // keep the element in the array
});
Note: The code above pulls the model from the view, as that's a best practice. Try not to tie anything to the core, as the core is shared between all applications running in the browser window (e.g. in Fiori Launch Pad scenario).
Hey UI5 is a framework which has many possibilities but sometimes I crush with ideas (which would be probably easier in normal HTML) against the walls.
That's what I want: A List with ListItems displaying Cities for example Berlin, Los Angeles, Moskau etc. On this listen you then can click on an icon (preferred but can be a button too). If clicked Icon displays then another ListItem so it displays an address. If you then lick that ListItem you get a map -the map part is working and it would work with the list if it would have one StandardListItem. The problem? It's bad for displaying things like I want!
Example:
Berlin -> click -> show -> 123456 Example Street
Moskau
Los Angeles
or:
Berlin
Moskau
Los Angeles -> click -> show -> 654321 Example Adress
code I have :
NOTE: I deleted some of the code so you get only the necessary part of it
view:
<List id="campusList"
items="{
path: '/',
sorter: {
path: 'city',
descending: false
}
}"
mode="SingleSelectMaster"
itemPress="handleListItemPress"
growing="true">
<InputListItem label="{city}" >
<core:Icon src="sap-icon://navigation-down-arrow" press="showDetails" />
<StandardListItem type="Navigation" title="{buildingName}" description="{buildingDesc}" />
</InputListItem>
</List>
controller:
jQuery.sap.require("www.adress.com.GeneralHelper");
sap.ui.controller("www.adress.com.LocationList", {
onInit: function() {
var bus = sap.ui.getCore().getEventBus();
bus.subscribe("content", "updateSuccess", this.updateSuccess, this);
sap.ui.getCore().getEventBus().publish("content", "update", {
id : "Location"
});
},
updateSuccess: function (channelID , eventID, data) {
if (data.id === "Location") {
var oModel = sap.ui.getCore().getModel("LocationModel");
oModel.setDefaultBindingMode(sap.ui.model.BindingMode.OneWay);
this.getView().setModel(oModel);
if (!jQuery.device.is.phone) {
//preselect entry
var self = this;
var oList = this.byId("campusList");
oList.attachUpdateFinished(function(evt) {
if (oList.getItems().length > 0) {
var oContext = new sap.ui.model.Context(self.getView().getModel(), "/0");
oList.setSelectedItem(oList.getItems()[0], true);
sap.ui.getCore().getEventBus().publish("nav", "to", {
id: "LocationDetail",
data : oContext
});
}
});
}
}
},
handleListItemPress : function (evt) {
sap.ui.getCore().getEventBus().publish("nav", "to", {
id : "LocationDetail",
data : evt.getParameters().listItem.getBindingContext()
});
}
});
and I also have a local-demo-data-json wich is loaded from a UpdateHelper.
PS:I would like to not use $().hide, $().show and other jquery things i would prefer UI5.
If you want to show or hide a list item you can use
myListItem.setVisible(true) //or
myListItem.setVisible(false)
but what you can also do is use a custom list item, put all the extra information into a new sap.m.Panel(), and add that Panel into your custom list item on click (and destroy it/set it to invisible to hide the extra information).
I has question about Localization,
I create key in Labels.js file, code :
Ext.define('Portal.Labels', {
singleton: true,
title: ''
});
And in event click of button, I using:
var main = Ext.getCmp('main'); // Get main (container) and destroy it.
main.destroy();
// Sure main is destroyed.
// Get url of local.
var url = Ext.util.Format.format('ext/packages/ext-locale/overrides/vn/ext-locale-vn.js');
// Sure url is loaded.
// Load script local file.
Ext.Loader.loadScript({
url: url,
scope: this
}
);
// Create main and show it.
main = Ext.create('main');
main.show();
In ext-locale-vn.js, I add :
Ext.define("Portal.locale.vn.Labels", {
override: "Portal.Labels",
title: "DASHBOARD"
});
In main container, I create lable:
xtype: 'label',
text:Portal.Labels.title
But when I click button, text of label still not change to "DASHBOARD", I don't know where I was wrong, please help me.
I am using Titanium Alloy version 3.2. I have a collection of posts in a listview. My data looks like this:
[
{ username: 'dude', imageUrl: 'url', tags: ['tag1','tag2','tag3'] },
{ username: 'wheres', imageUrl: 'url', tags: ['tag1'] },
{ username: 'my', imageUrl: 'url', tags: ['tag1','tag2','tag3','tag4'] },
{ username: 'car', imageUrl: 'url', tags: ['tag1','tag2'] }
]
And here is the xml. This works only for username and image. I can't figure out how to add the tags to each post.
<ListView id="streamListview">
<Templates>
<ItemTemplate name="template" id="template">
<View class="item-container">
<ImageView bindId="pic" class="pic"/>
<Label bindId="username" class="username"/>
</View>
</ItemTemplate>
</Templates>
<ListSection id="section">
<ListItem template="template" class="list-item"/>
</ListSection>
</ListView>
And my controller code (without the tags)
var posts = [];
for (var i=0; i<data.length; i++){
var post = {
template : "template",
pic : { image : data[i].get("imageUrl") },
username : { text : data[i].get("username") }
};
posts.push(post);
}
$.section.setItems(posts);
How can I add tags (that are clickable) to the post if I am supposed to declare EVERY view in the template before hand? Each tags array in my example would need a different number of views depending on the array length. Each tag would ideally be its own UI.Label element. I believe this can be done using a TableView, but I would prefer using ListView for performance reasons.
I think I know what you need, in this case since you want to generate each item dynamically (for example, a scenario where you open your window with your ListView empty first and make an API call to get remote data and fill the ListView with said data) you will need to use ItemTemplates declared in their own controllers.
You just create a new controller like normal and in the view xml you put your ItemTemplate:
<Alloy>
<ItemTemplate name="template" id="template">
<View class="item-container">
<ImageView bindId="pic" class="pic"/>
<Label bindId="username" class="username"/>
</View>
</ItemTemplate>
</Alloy>
In your tss you put all of the styles referred to each element in your template, since you didn't provide a tss example I can't tell what are your style properties, but in the tss you need to define the style of the template, for example lets say something like:
"#template": // this is the id of your template in your xml
{
width : Ti.UI.FILL,
height : '44dp',
backgroundColor : '#FFFFFF'
}
To fill your ListView with ListItems dynamically, you will need to do something like this in your callback from your API:
function displayListItems(items)
{
var itemCollection = [];
for(var i=0; i < items.length; i++)
{
var tmp = {
pic : {
image : items[i].image
},
username : {
text : items[i].text
},
template : 'template' // here goes the name of the template in your xml, **do not confuse name with id, both are different and using one doesn't replace the other**
};
itemCollection.push(tmp);
}
$.ListView.sections[0].items = itemCollection;
}
And voila, you get your ListView filled dynamically. Now there are some extra steps you can do.
In your template controller you can leave it blank since the ListView can manage the itemclick event, but if you want different actions to take place when a certain element in the Listitem to trigger, you need to specify the functions to be called in your controller for each element.
For example lets say you passed a property called dataInfo to your ImageView and your Label in your template like this:
function displayListItems(items)
{
var itemCollection = [];
for(var i=0; i < items.length; i++)
{
var tmp = {
pic : {
image : items[i].image
dataInfo : items[i].fooA //lets pass to the ImageView the object fooA
},
username : {
text : items[i].text,
dataInfo : items[i].fooB //lets pass to the Label the object fooB
},
template : 'template' // here goes the name of the template in your xml, **do not confuse name with id, both are different and using one doesn't replace the other**
};
itemCollection.push(tmp);
}
$.ListView.sections[0].items = itemCollection;
}
And you want the ImageView and the Label to call different functions, you will need to change your xml like this:
<Alloy>
<ItemTemplate name="template" id="template">
<View class="item-container">
<ImageView bindId="pic" class="pic" onClick="imageFunction"/> <!-- added onClick event -->
<Label bindId="username" class="username" onClick="labelFunction"/> <!-- added onClick event -->
</View>
</ItemTemplate>
</Alloy>
In your controller you will declare each function:
function imageFunction(e)
{
var dataInfo;
if(Ti.Platform.osname === 'android')
{
var item = e.section.items[e.itemIndex];
var bindObject = item[e.bindId];
dataInfo = bindObject.fooA;
}
else
{
dataInfo = e.source.fooA;
}
}
function labelFunction(e)
{
var dataInfo;
if(Ti.Platform.osname === 'android')
{
var item = e.section.items[e.itemIndex];
var bindObject = item[e.bindId];
dataInfo = bindObject.fooB;
}
else
{
dataInfo = e.source.fooB;
}
}
Now you might ask, why do check for the operative system name, well that is because Android and iOS receive different e objects even if you use the same function. In iOS whatever property you pass to the source of the event can be accessed directly with e.source.propertyName while in Android you need to access to the item in e.section using e.itemIndex, after that you retrieve the view inside the item with the e.bindId associated to it.
One of the biggest restrictions on ListItems is updating the views inside a ListItem, to do this you need to update the whole item you want to change visually and assign it a different template, but the speed at which this is done you won't be able to notice any lag, seriously ListView's performance is something else, unlike ScrollView and let's not talk about the horrible and buggy TableView.
A warning, as of Titanium SDK 3.2.0.GA there's a bug in ItemTemplates that causes for views inside child views in the template to change their zIndex in Android with no way to control it, there are two known instances for this:
If you use a don't set the layout in a child view: this could cause for a view that should be displayed beneath another view to come on top of it.
If you use a vertical layout in a child view: this could cause for the positions of each view to be scrambled, this is because zIndex alters the order of display in a vertical layout.
This bug is triggered randomly and the Appcelerator team hasn't put much work on it, check the JIRA ticket here TIMOB-16704.
This can be avoided if you use a template with fixed positioned views and making sure no view comes on top of another, also remember no vertical layouts, haven't tested this with horizontal but personally I try to avoid horizontal layouts since there are other bugs related to it when used in scrollviews, normal views, etc.
EDIT
Another thing you might want to do with this is to assign a different look to the items you render, you have to options:
To apply the styles when you declare the ListItem.
To apply a different layout to each ListItem depending on a series of conditions.
For the first option you need to omit or overwrite the declaration of certain properties in your template:
For example, let's use a different background color where the property fooA exists and another color if it doesn't:
function displayListItems(items)
{
var itemCollection = [];
for(var i=0; i < items.length; i++)
{
var properties = {};
if(typeof items[i].fooA !== 'undefined')
{
properties = {
backgroundColor : 'red'
};
}
else
{
properties = {
backgroundColor : 'blue'
};
}
var tmp = {
properties : properties, // properties for the template
pic : {
image : items[i].image
dataInfo : items[i].fooA //lets pass to the ImageView the object fooA
},
username : {
text : items[i].text,
dataInfo : items[i].fooB //lets pass to the Label the object fooB
},
template : 'template' // here goes the name of the template in your xml, **do not confuse name with id, both are different and using one doesn't replace the other**
};
itemCollection.push(tmp);
}
$.ListView.sections[0].items = itemCollection;
}
You can change width, height, backgroundColor, layout, etc. according to your needs.
Now if you want each item to have a distinct look (meaning different views to display different content) and perhaps a different behavior, you'll need to use different templates.
This might sound bothersome but it is not, templates are fast to create once you get used to them which doesn't take long, another downer might be that if you want 11 different looks, that might mean you'll need 11 templates but that's a extreme case and you might want to rethink your UI if you're dealing with that many templates.
Although restrictive, item templates offer a wide array of options for you to use, a little of imagination is the only ingredient necessary to bring out all of the possibilities.
EDIT 2
I finally understood what was you problem, if you need to create a template whose content changes according to a x variable, then you should try declaring the template on your ListView controller, but this should be done before opening the window were you will be showing the ListView since the templates property can only be set on creation, you should add something like:
function createTemplate(items)
{
var template = {};
for(var i=0; i < items.length; i++)
{
template.childTemplates = [];
for(var j=0; items[i].tags.length; j++)
{
var childTemplate = {
type: 'Ti.UI.Label',
bindId: 'tag' + j,
properties : {
width : Ti.UI.SIZE, // Here you define how your style
height : Ti.UI.SIZE,
font : {
fontSize : '18dp'
},
text : items[i].tags[j].text // you can pass the text here or if you want to on the later for
}
};
template.childTemplates.push(childTemplate);
}
}
// After this you should end up with a template with as many childTemplates as tags each item have, so send the template to the controller with your ListView
Alloy.createController('ListViewWindow', {customTemplate: template});
}
And in your ListView controller you retrieve the template:
var args = arguments[0] || {};
var template = args.customTemplate;
$.ListView.templates = {'customTemplate' : template}; // before any window open call, do this
This should add the template to your ListView, you can also create the ListView in your controller instead of declaring it in your Alloy xml, use the one that fits your needs more.
This should be possible with a ListView if you create the template in the controller dynamically. You would also need to iterate through each "tags" object and generate a Ti.UI.Label "type" for each tag item. However, I'm not certain this method will be more efficient than using a TableView object because essentially every ListItem you create will contain a different template.
To generate a dynamic template it would be similar to this below: Keep in mind you will need to iterate over "tags" and generate x Ti.UI.Label types where x is the length of "tags". Also, the click event should work using Titanium SDK 3.2.1.
var plainTemplate = {
childTemplates: [
{
type: 'Ti.UI.Label',
bindId: 'username'
},
{
type: 'Ti.UI.ImageView',
bindId: 'pic'
},
{
type: 'Ti.UI.Label',
bindId: 'tags',
events: { click : handleTagClickEvent } // Binds a callback to click event
}
]};
function handleTagClickEvent(e) {
Ti.API.info('You clicked a tag label: ' + e.type);
}
var listView = Ti.UI.createListView({
templates: { 'plain': plainTemplate },
defaultItemTemplate: 'plain'
});
Hope this helps you in some way!
In my MVC application in Controller i have following function to add and focus new tab to TabPanel with DataView inside:
show_gallery: function(view, record, item, index, e, opts) {
var tabb = Ext.ComponentQuery.query('.gallery_panel');
var gallery_view = Ext.widget('gallery_view');
var ImageStore = Ext.create('Gallery.store.Images');
ImageStore.load({url: 'myphoto/index.php/api/feed/json/' + record.data.uuid});
Ext.apply(gallery_view, {
title: record.data.name,
id: record.data.uuid,
closable:true,
store: ImageStore
});
if (tabb[0].down('#' + record.data.uuid)) {
console.log('Entered IF');
//tabb[0].setActiveTab(tabb[0].down('#' + record.data.uuid));
tabb[0].setActiveTab(record.data.uuid);
}else{
console.log('Entered ELSE');
tabb[0].add(gallery_view);
if (Ext.getCmp(record.data.uuid)) {
console.log('THERE IS SUCH UUID');
}
//tabb[0].setActiveTab(gallery_view);
}
},
And the problem is in the last line. When i uncomment tabb[0].setActiveTab(gallery_view) the new tab is focused but empty and if i leave the line commented the new tab with dataView is populated with data but not focused. I really dont have any idea why setActiveTab() causes DataView not to display at all. The gallery_view widget is Ext.view.View extension.
I'm not sure how come you get the data view if there's no setActiveTab, but there seem to be some issue with this code:
var gallery_view = Ext.widget('gallery_view');
var ImageStore = Ext.create('Gallery.store.Images');
ImageStore.load({url: 'myphoto/index.php/api/feed/json/' + record.data.uuid});
Ext.apply(gallery_view, {
title: record.data.name,
id: record.data.uuid,
closable:true,
store: ImageStore
});
First you create a new widget with Ext.widget() and then you override some config options with Ext.apply(). To my understanding, the latter is fine for primitives but not for objects/arrays.
Generally speaking, the configs are there for the purpose of telling the constructor how to initialise a specific instance of the class. A change to an object's title through Ext.apply() could work if the object is not rendered yet, but not a change to a store config (upon construction the component might start listening to various store events, this won't happen by a simple Ext.apply() which only copies configs from one object to another - you've already missed the train for a component that was created as far as listening to store events goes).
Please try this instead:
var ImageStore = Ext.create('Gallery.store.Images');
ImageStore.load({url: 'myphoto/index.php/api/feed/json/' + record.data.uuid});
var gallery_view = Ext.widget('gallery_view', {
title: record.data.name,
id: record.data.uuid,
closable:true,
store: ImageStore
});